#!/usr/bin/env python

import re
from datetime import datetime, time, tzinfo, timedelta

DATE = r"(?P<year>-?\d{4,})-(?P<month>\d{2})-(?P<day>\d{2})"
TIME = r"(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})(?P<microsecond>\.\d+)?"
TIMEZONE = r"((?P<utc>Z)|(?P<tzsign>[+-])(?P<tzhour>\d{2}):(?P<tzminute>\d{2}))?"

DATE_REGEX = re.compile(
        r"^"
        + DATE
        + TIMEZONE + 
        r"$"
)

TIME_REGEX = re.compile(
        r"^"
        + TIME
        + TIMEZONE + 
        r"$"
)

DATETIME_REGEX = re.compile(
        r"^"
        + DATE +
        r"T"
        + TIME
        + TIMEZONE + 
        r"$"
)

class Timezone(tzinfo):
    def __init__(self, sign, tzhour, tzminute):
        self.sign = sign
        self.tzhour = tzhour
        self.tzminute = tzminute
        
    
    def utcoffset(self, dt):
        delta = timedelta(hours = self.tzhour, minutes = self.tzminute)
        if self.sign == '+':
            return delta
        else:
            return -delta



class UTC(tzinfo):
    delta = timedelta()
    
    @classmethod
    def utcoffset(cls, dt):
        return cls.delta


def tz_from_groups(groups):    
    if groups['utc']:
        return UTC()
    elif groups['tzsign']:
        return Timezone(groups['tzsign'], int(groups['tzhour']), int(groups['tzminute']))
    else:
        return None
        
        
def date_from_groups(groups):
    return [
        int(groups['year']), 
        int(groups['month']), 
        int(groups['day'])
    ]


def time_from_groups(groups):
    return [
        int(groups['hour']), 
        int(groups['minute']), 
        int(groups['second']), 
        int(float(groups['microsecond'] or 0)*10**6)
    ]


def parse_xsdate(string):
    m = DATE_REGEX.match(string)

    if not m:
        raise ValueError("given string is not in xs:date format")
        
    groups = m.groupdict()
    tz = tz_from_groups(groups)
        
    return datetime(*(date_from_groups(groups)+[0, 0, 0, 0, tz]))
    

def parse_xstime(string):
    m = TIME_REGEX.match(string)

    if not m:
        raise ValueError("given string is not in xs:time format")
        
    groups = m.groupdict()
    tz = tz_from_groups(groups)

    return time(*(time_from_groups(groups)+[tz]))


def parse_xsdatetime(string):
    m = DATETIME_REGEX.match(string)

    if not m:
        raise ValueError("given string is not in xs:dateTime format")
    
    groups = m.groupdict()
    tz = tz_from_groups(groups)
        
    return datetime(*(date_from_groups(groups)+time_from_groups(groups)+[tz]))
